在 Day02 的快速入門中,我們建立了一個基礎的 HttpUser
來對 API 進行測試。然而,要精準模擬真實世界的使用者行為,我們需要更深入地了解 Locust 的核心組件,包含 User
與 HttpUser
的差異、任務的權重設定 (@task(weight)
), 以及使用者等待時間 (wait_time
) 的不同策略。
今天,我們將深入探討這些概念,並學習如何同時模擬多種不同的使用者類型。
在 Locust 中,所有模擬使用者都繼承自 User
類別。User
是最基礎的抽象類別,而 HttpUser
則是它的一個特化版本。
User
:
這是最通用的使用者類別,它本身不具備任何特定的網路協定能力。當您需要測試非 HTTP 的系統時,例如 gRPC、WebSocket 或其他自訂 TCP/IP 協定,就應該繼承自 User
類別,並自行實現客戶端邏輯。
基礎範例 (無任務):
from locust import User, between
class MyCustomUser(User):
wait_time = between(1, 5)
HttpUser
:
這是最常用的使用者類別,專為測試 HTTP/HTTPS 服務(如網站、API)而設計。它繼承自 User
,並內建了一個強大的 HTTP 客戶端 self.client
(基於 requests
)。透過這個客戶端,我們可以輕易地發送 GET, POST, PUT 等請求。
基礎範例 (無任務):
from locust import HttpUser, between
class MyWebAppUser(HttpUser):
wait_time = between(1, 5)
host = "https://example.com"
在真實情境中,使用者執行的不同操作頻率可能不同。例如,瀏覽商品的使用者數量遠大於下訂單的使用者。Locust 允許我們使用 @task
裝飾器的參數來設定任務的「權重」,以模擬這種行為。
一個任務的權重越高,它被選中執行的機率就越大。如果所有任務都沒有設定權重,則它們被選中的機率相等。
範例:
假設一個電商網站,使用者有 80% 的時間在瀏覽商品,20% 的時間在查看個人檔案。我們可以這樣設定:
from locust import HttpUser, task, between
class WebsiteUser(HttpUser):
wait_time = between(1, 5)
host = "http://localhost:8080"
@task(4) # 權重設為 4
def view_products(self):
print("I am viewing products.")
@task(1) # 權重設為 1
def view_profile(self):
print("I am viewing my profile.")
更改範例後記得要重啟終端機的 locust 並重整網頁
在這個例子中,view_products
任務被執行的機率是 view_profile
的 4 倍,這更貼近真實的使用者行為模式。在下面這張圖片可以看到印出 “I am viewing products.” 的機率要比 “I am viewing profile.” 的機率高出不少:
特性 | User |
HttpUser |
---|---|---|
基礎類別 | 是,所有使用者的基礎 | 否,繼承自 User |
內建客戶端 | 否 | 是 (self.client ),用於 HTTP/S |
主要用途 | 測試非 HTTP 協定 (gRPC, WebSocket) | 測試網站、API 等 HTTP/S 服務 |
範例場景 | 遊戲伺服器、訊息佇列 | 電商網站、RESTful API |
wait_time
屬性wait_time
用於模擬使用者在執行下一個任務前的「思考時間」,這對於建立更真實的負載模式至關重要。Locust 提供了三種主要的等待策略:
between(min, max)
:
這是最常用的策略。它會讓模擬使用者在每次任務執行後,隨機等待 min
到 max
秒之間的一個時間。這能很好地模擬真實使用者行為的隨機性。
from locust import HttpUser, task, between
class WebsiteUser(HttpUser):
wait_time = between(1, 5)
host = "http://localhost:8080"
@task(4) # 權重設為 4
def test_hello_world_endpoint(self):
self.client.get("/hello-world")
constant(wait_seconds)
:
此策略讓模擬使用者在每次任務後,都等待一個固定的秒數。這在需要精確控制請求間隔的場景中很有用,但較不符合真實使用者的隨機行為。
from locust import HttpUser, task, constant
class WebsiteUser(HttpUser):
wait_time = constant(5)
host = "http://localhost:8080"
@task(4) # 權重設為 4
def test_hello_world_endpoint(self):
self.client.get("/hello-world")
constant_pacing(wait_seconds)
:
這是一個更進階的策略,它能確保一個任務的執行週期(包含任務執行時間與等待時間)總和為一個固定的秒數。如果任務執行時間超過了設定的秒數,則等待時間為 0。這對於達成特定的吞吐量 (RPS, Requests Per Second) 非常有用。
from locust import HttpUser, task, constant_pacing
class WebsiteUser(HttpUser):
wait_time = constant_pacing(5)
host = "http://localhost:8080"
@task(4) # 權重設為 4
def test_hello_world_endpoint(self):
self.client.get("/hello-world")
可以看到在下圖中 “Total Requests per Second” 的地方,除了一開始剛進行測試之外,後續的平均請求次數就逐漸趨於穩定。
在真實世界中,一個系統通常會有多種類型的使用者,例如:匿名訪客、普通會員、後台管理員。他們的行為模式和權限都不同。Locust 允許我們在同一個測試腳本中定義多個 User
類別來模擬這種複雜情境。
Locust 本身沒有 MultipleUser
或 MultipleHttpUser
這樣的類別。要實現多使用者模擬,您只需要在 locustfile 中定義多個繼承自 User
或 HttpUser
的類別即可。
執行範例:
假設我們要同時模擬兩種使用者:一種是頻繁瀏覽網站的普通用戶 (WebAppUser
),另一種是偶爾呼叫特定 API 的數據分析師 (DataAnalystUser
)。
from locust import HttpUser, task, between
# 第一種使用者:網站訪客
class WebAppUser(HttpUser):
wait_time = between(1, 3)
host = "http://localhost:8080"
# 權重為 2,表示這類使用者行為較頻繁
weight = 2
@task
def homepage(self):
print("WebAppUser: Visiting homepage")
# self.client.get("/")
@task
def about_page(self):
print("WebAppUser: Visiting about page")
# self.client.get("/about")
# 第二種使用者:數據分析師
class DataAnalystUser(HttpUser):
wait_time = between(5, 10)
host = "http://localhost:8080"
# 權重為 1,表示這類使用者較少
weight = 1
@task
def get_analytics_data(self):
print("DataAnalystUser: Fetching analytics data")
# self.client.get("/api/v1/analytics")
當您使用 locust -f demo.py
啟動這個腳本時,Locust 的 Web UI 會讓您分別設定要模擬的 WebAppUser
和 DataAnalystUser
的數量。Locust 會根據您設定的比例以及類別中定義的 weight
屬性來產生負載。
由於我們這裡這定了兩個 User,重啟 locust 後記得使用者的數量要至少設定兩個,才可以看得出效果!
按下 START 開始執行後,應該可以在終端機上看到如下圖中的效果,WebAppUser
和 DataAnalystUser
交替著出現:
透過這些進階功能,您可以更靈活、更真實地模擬複雜的使用者場景,從而更準確地評估您的系統效能。
今天我們深入了解了如何定義與客製化使用者行為。明天,我們將轉換視角,探討 Locust 的運作流程以及更多元的執行方法,敬請期待!